package com.da.web.sys_login.service.impl;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.da.common.Result;
import com.da.exception.MyException;
import com.da.utils.IpUtil;
import com.da.utils.RedisUtil;
import com.da.web.school_student.entity.SchoolStudent;
import com.da.web.school_student.service.SchoolStudentService;
import com.da.web.sys_login.entity.*;
import com.da.web.sys_login.service.LoginService;
import com.da.web.sys_menu.entity.MakeTree;
import com.da.web.sys_menu.entity.SysMenu;
import com.da.web.sys_menu.service.SysMenuService;
import com.da.web.sys_role.entity.SysRole;
import com.da.web.sys_role.service.SysRoleService;
import com.da.web.sys_user.entity.SysUser;
import com.da.web.sys_user.service.SysUserService;
import com.google.code.kaptcha.Producer;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author da
 * @time 2023/12/21 下午 1:53
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SchoolStudentService schoolStudentService;
    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private Producer producer;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IpUtil ipUtil;


    //登录
    @Override
    public Result login(LoginParm parm, HttpServletRequest request) {
        //先验证账号、密码和用户类型
        if (StrUtil.isEmpty(parm.getUsername()) || StrUtil.isEmpty(parm.getPassword()) || StrUtil.isEmpty(parm.getUserType())) {
            return Result.error("账户或者密码不能为空");
        }
        //再验证验证码
        if (StrUtil.isEmpty(parm.getCode())) {
            return Result.error("验证码不能为空");
        }
        //通过request对象获取保存在redis中的值
        String key = getCodeKey(request);
        //获取值
        Object o = redisUtil.get(key);
        if (o == null) {
            return Result.error("验证码已过期");
        }
        //判断值是否相等
        if (!parm.getCode().equals(o.toString())) {
            return Result.error("验证码错误");
        }
        //把传来的密码加密,然后与数据库中的比较
        String password = DigestUtils.md5DigestAsHex(parm.getPassword().getBytes());
        //管理员登录
        if (parm.getUserType().equals("1")) {
            return adminLogin(parm, password);
        } else {
            //学生登录
            return studentLogin(parm, password);
        }
    }

    //学生登录
    private Result studentLogin(LoginParm parm, String password) {
        QueryWrapper<SchoolStudent> query = new QueryWrapper<>();
        query.lambda().eq(SchoolStudent::getStuNum, parm.getUsername())
                .eq(SchoolStudent::getPassword, password);
        SchoolStudent student = schoolStudentService.getOne(query);
        if (student == null) {
            throw new MyException(500, "账户或者密码错误");
        }
        //        登录
        StpUtil.login(student.getStuId(),
                SaLoginConfig.setExtra("stuId", student.getStuId())
                        .setExtra("stuNum", student.getStuNum())
                        .setExtra("stuName", student.getStuName())
        );
        //  生成token
        String tokenValue = StpUtil.getTokenValue();
        //设置返回数据
        LoginResult result = new LoginResult();
        result.setUserId(student.getStuId());
        result.setUsername(student.getStuName());
        result.setUserType(parm.getUserType());
        result.setToken(tokenValue);
        return Result.success("登录成功", result);
    }

    //管理员登录
    private Result adminLogin(LoginParm parm, String password) {
        QueryWrapper<SysUser> query = new QueryWrapper<>();
        query.lambda().eq(SysUser::getUsername, parm.getUsername()).eq(SysUser::getPassword, password);
        SysUser user = sysUserService.getOne(query);
        if (user == null) {
            throw new MyException(500, "账户或者密码错误");
        }
        // 登录
        StpUtil.login(user.getUserId(),
                SaLoginConfig.setExtra("userId", user.getUserId())
                        .setExtra("userName", user.getUsername())
                        .setExtra("nickName", user.getNickName())
        );
        //  生成token
        String tokenValue = StpUtil.getTokenValue();
        //设置返回数据
        LoginResult result = new LoginResult();
        result.setUserId(user.getUserId());
        result.setUsername(user.getUsername());
        result.setUserType(parm.getUserType());
        result.setToken(tokenValue);
        return Result.success("登录成功", result);
    }

    //获取用户信息
    @Override
    public Result getInfo(Long userId, String userType) {
        //默认头像
        String defaultAvatar = "";
        if (userType.equals("1")) {
            return getAdminInfo(userId, defaultAvatar);
        } else {
            return getStudentInfo(userId, defaultAvatar);
        }
    }

    //获取用户(学生)信息
    private Result getStudentInfo(Long userId, String defaultAvatar) {
        SchoolStudent student = schoolStudentService.getById(userId);
        UserInfo userInfo = new UserInfo();
        userInfo.setIntroduction(student.getStuName());
        userInfo.setName(student.getStuNum());
        if (student.getAvatar() == null || student.getAvatar().isEmpty()) {
            userInfo.setAvatar(defaultAvatar);
        } else {
            userInfo.setAvatar(student.getAvatar());
        }
        //通过学生id查询用户的权限字段
        List<SysMenu> menuList = sysMenuService.getStuMenuByUserId(userId);
        //设置返回的用户信息
        return getResult(userInfo, menuList);
    }

    //获取管理员信息
    private Result getAdminInfo(Long userId, String defaultAvatar) {
        SysUser user = sysUserService.getById(userId);
        UserInfo userInfo = new UserInfo();
        userInfo.setIntroduction(user.getNickName());
        userInfo.setName(user.getUsername());
        if (user.getAvatar() == null || user.getAvatar().isEmpty()) {
            userInfo.setAvatar(defaultAvatar);
        } else {
            userInfo.setAvatar(user.getAvatar());
        }
        //查询用户的权限字段
        List<SysMenu> menuList;
        //如果是管理员就返回全部的
        if (user.getIsAdmin().equals("1")) {
            menuList = sysMenuService.list();
        } else {
            menuList = sysMenuService.getMenuByUserId(userId);
        }
        //获取code字段
        return getResult(userInfo, menuList);
    }

    //设置返回的用户信息
    private Result getResult(UserInfo userInfo, List<SysMenu> menuList) {
        List<String> collect = menuList.stream()
                .filter(item -> item != null && item.getCode() != null && StrUtil.isNotEmpty(item.getCode()))
                .map(SysMenu::getCode)
                .toList();
        if (collect.isEmpty()) {
            return Result.error("未分配权限,请联系管理员");
        } else {
            String[] array = collect.toArray(new String[0]);
            //设置用户的权限字段
            userInfo.setRoles(array);
            return Result.success("查询成功", userInfo);
        }
    }

    //获取用户菜单
    @Override
    public Result getMenuList(Long userId, String userType) {
        //根据用户id查询菜单
        List<SysMenu> menuList;
        if (userType.equals("1")) {
            SysUser user = sysUserService.getById(userId);
            //管理员有全部的菜单
            if (user.getIsAdmin().equals("1")) {
                menuList = sysMenuService.list();
            } else {
                menuList = sysMenuService.getMenuByUserId(userId);
            }
        } else {
            //通过学生id获取对应的菜单
            menuList = sysMenuService.getStuMenuByUserId(userId);
        }
        if (menuList == null || menuList.isEmpty()) {
            return Result.error("未分配权限,请联系管理员");
        }
        //筛选出 目录和菜单
        List<SysMenu> collect = menuList.stream().filter(item -> item != null && !item.getType().equals("2"))
                .collect(Collectors.toList());
        List<RouterVo> routes = MakeTree.makeRouter(collect, 0L);
        return Result.success("查询成功", routes);
    }

    //更新用户信息
    @Override
    public Result updateInfo(UpdateVo userInfo) {
        String password = DigestUtils.md5DigestAsHex(userInfo.getPassword().getBytes());
        //要更新的密码
        String newPassword = DigestUtils.md5DigestAsHex(userInfo.getNewPassword().getBytes());
        if (userInfo.getUserType().equals("1")) {
            QueryWrapper<SysUser> sysQuery = new QueryWrapper<>();
            sysQuery.lambda().eq(SysUser::getUsername, userInfo.getName())
                    .eq(SysUser::getPassword, password);
            SysUser user = sysUserService.getOne(sysQuery);
            if (user != null) {
                user.setAvatar(userInfo.getAvatar());
                user.setNickName(userInfo.getIntroduction());
                user.setPassword(newPassword);
                boolean b = sysUserService.updateById(user);
                if (b) {
                    return Result.success("更新成功");
                } else {
                    return Result.success("更新失败");
                }
            } else {
                throw new MyException(500, "原始密码错误");
            }
        } else {
            QueryWrapper<SchoolStudent> stuQuery = new QueryWrapper<>();
            //根据学号来更新对应的学生信息
            stuQuery.lambda().eq(SchoolStudent::getStuNum, userInfo.getName())
                    .eq(SchoolStudent::getPassword, password);
            SchoolStudent user = schoolStudentService.getOne(stuQuery);
            if (user != null) {
                user.setAvatar(userInfo.getAvatar());
                user.setStuName(userInfo.getIntroduction());
                user.setPassword(newPassword);
                boolean b = schoolStudentService.updateById(user);
                if (b) {
                    return Result.success("更新成功");
                } else {
                    return Result.success("更新失败");
                }
            } else {
                throw new MyException(500, "原始密码错误");
            }
        }
    }

    @Override
    public void getCode(HttpServletRequest request, HttpServletResponse response) {
        try {
            //获取redis中存储验证码的key
            String key = getCodeKey(request);
            //这里的text即为kaptcha生成的验证码中的文字
            String text = producer.createText();
            //存储验证码到redis中,15秒过期
            redisUtil.set(key, text, 15);
            log.info("生成的验证码为 => {}", text);
            //这里的imagr即为kaptcha通过生成text生成的验证码
            BufferedImage image = producer.createImage(text);
            //设置响应头
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            response.setContentType("image/jpeg");
            OutputStream outputStream = response.getOutputStream();
            //把图片写到浏览器
            ImageIO.write(image, "jpg", outputStream);
            IOUtils.closeQuietly(outputStream);
        } catch (IOException e) {
            throw new MyException(500, "获取验证码失败");
        }
    }

    @Override
    public Result getRoleTypes() {
        List<SysRole> list = sysRoleService.list();
        return Result.success("获取成功", list);
    }

    //生成redis中验证码的key
    private String getCodeKey(HttpServletRequest request) {
        //验证码的key为ip地址加上code的MD5值
        String key = ipUtil.getIpAddr(request) + "code";
        key = DigestUtils.md5DigestAsHex(key.getBytes(StandardCharsets.UTF_8));
        return key;
    }
}
